﻿using AF_Application.Interface.Cache;
using Couchbase;
using Couchbase.Configuration.Client;
using Couchbase.Configuration.Client.Providers;
using Couchbase.Core;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AF_Web;
using System.Configuration;
using System.Threading;

namespace AF_Cache
{
    /// <summary>
    /// 此类在IOC中以单例模式加载。
    /// </summary>
    public class CouchbaseCacheProvider : ICacheProvider
    {
        private static readonly object lockObj = new object();
        private uint AppCacheSeconds = 300;
        private string DefBucketName;
        private string DefBucketPassword;
        private string AppName;
        private ICluster MyCluster;
        private Dictionary<string, IBucket> BucketList = new Dictionary<string, IBucket>();

        public CouchbaseCacheProvider()
        {
            AppName = ConfigurationManager.AppSettings.GetString("AppName");
            if (string.IsNullOrEmpty(AppName))
            {
                throw new Exception("请在Config文件AppSetting中配置AppName项");
            }

            AppCacheSeconds = (uint)ConfigurationManager.AppSettings.GetInt("AppCacheSeconds");
            DefBucketName = ConfigurationManager.AppSettings.GetString("AppDataBucketName");
            DefBucketPassword = ConfigurationManager.AppSettings.GetString("AppDataBucketPassword");
            MyCluster = new Cluster("couchbaseClients/couchbase");
            BucketList.Clear();
        }

        private IBucket GetBucket(string bucket, string password = "")
        {
            IBucket Instance = null;
            if (BucketList.Keys.Contains(bucket))
            {
                Instance = BucketList[bucket];
            }
            if (Instance == null)
            {
                if (string.IsNullOrWhiteSpace(password))
                {
                    Instance = MyCluster.OpenBucket(bucket);
                }
                else
                {
                    Instance = MyCluster.OpenBucket(bucket, password);
                }
                BucketList.Add(bucket, Instance);
            }
            return Instance;
        }

        public void Dispose()
        {
            BucketList.Clear();
            MyCluster.Dispose();
        }

        public bool Set<T>(string key, T data, uint lifeSeconds = 0, string bucket = "", string password = "")
        {
            bool result = false;
            IOperationResult Result = null;

            if (!string.IsNullOrEmpty(key))
            {
                string _Bucket = DefBucketName;
                string _Password = DefBucketPassword;
                if (!string.IsNullOrEmpty(bucket))
                {
                    _Bucket = bucket;
                }
                if (!string.IsNullOrEmpty(password))
                {
                    _Password = password;
                };
                IBucket Bucket = GetBucket(_Bucket, _Password);
                if (Bucket != null)
                {
                    CacheEntity<T> Data = new CacheEntity<T>() { DataType = typeof(T).Name, AppName = AppName, Data = data };
                    string jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(Data);
                    
                    if (lifeSeconds > 0)
                    {
                        Result = Bucket.Upsert((AppName + "_" + key).ToLower(), jsonData, lifeSeconds);
                    }
                    else
                    {
                        Result = Bucket.Upsert((AppName + "_" + key).ToLower(), jsonData);
                    }
                }
                return Result != null && Result.Success;
            }
            return result;
        }

        public T Get<T>(string key, string bucket = "", string password = "")
        {
            T result = default(T);
            if (!string.IsNullOrEmpty(key))
            {
                string _Bucket = DefBucketName;
                string _Password = DefBucketPassword;
                if (!string.IsNullOrEmpty(bucket))
                {
                    _Bucket = bucket;
                }
                if (!string.IsNullOrEmpty(password))
                {
                    _Password = password;
                };
                IBucket Bucket = GetBucket(_Bucket, _Password);
                if (Bucket != null)
                {
                    var Result = Bucket.Get<string>((AppName + "_" + key).ToLower());
                    if (Result != null && Result.Success)
                    {
                        string jsonData = Result.Value;
                        CacheEntity<T> ResultData = Newtonsoft.Json.JsonConvert.DeserializeObject<CacheEntity<T>>(jsonData);
                        result = ResultData.Data;
                    }
                }
            }
            return result;
        }

        public object Get(string key, Type type, string bucket = "", string password = "")
        {
            object result = null;
            if (!string.IsNullOrEmpty(key))
            {
                string _Bucket = DefBucketName;
                string _Password = DefBucketPassword;
                if (!string.IsNullOrEmpty(bucket))
                {
                    _Bucket = bucket;
                }
                if (!string.IsNullOrEmpty(password))
                {
                    _Password = password;
                };
                IBucket Bucket = GetBucket(_Bucket, _Password);
                if (Bucket != null)
                {
                    var Result = Bucket.Get<object>((AppName + "_" + key).ToLower());
                    if (Result != null && Result.Success)
                    {
                        JObject JOBJ = JObject.Parse(Result.Value.ToString());
                        string DataJson = JOBJ["Data"].ToString();
                        result = Newtonsoft.Json.JsonConvert.DeserializeObject(DataJson, type);
                    }
                }
            }
            return result;
        }


        public bool Remove(string key, string bucket = "", string password = "")
        {
            bool result = false;
            if (!string.IsNullOrEmpty(key))
            {
                string _Bucket = DefBucketName;
                string _Password = DefBucketPassword;
                if (!string.IsNullOrEmpty(bucket))
                {
                    _Bucket = bucket;
                }
                if (!string.IsNullOrEmpty(password))
                {
                    _Password = password;
                };
                 IBucket Bucket = GetBucket(_Bucket, _Password);
                 if (Bucket != null)
                 {
                     var Result = Bucket.Remove((AppName + "_" + key).ToLower());
                     result = Result != null && Result.Success;
                 }
            }
            return result;
        }

        public List<T> GetViewData<T>(string docName, string viewName, int pageIndex, int pageSize, out int totalRows, bool isDevView = false, string bucket = "", string password = "")
        {
            totalRows = 0;
            List<T> result = null;
            if (!string.IsNullOrEmpty(docName))
            {
                string _Bucket = DefBucketName;
                string _Password = DefBucketPassword;
                if (!string.IsNullOrEmpty(bucket))
                {
                    _Bucket = bucket;
                }
                if (!string.IsNullOrEmpty(password))
                {
                    _Password = password;
                };
                 IBucket Bucket = GetBucket(_Bucket, _Password);
                 if (Bucket != null)
                 {
                     var query = Bucket.CreateQuery(docName, viewName, isDevView).Limit(pageSize).Skip(pageSize * pageIndex);
                     var data = Bucket.Query<T>(query);
                     if (data != null && data.Success)
                     {
                         totalRows = (int)data.TotalRows;
                         result = data.Rows.Select(p => p.Value).ToList();
                     }
                 }
            }
            return result;
        }

        public bool Exists(string key, string bucket = "", string password = "")
        {
            bool result = false;
            if (!string.IsNullOrEmpty(key))
            {
                string _Bucket = DefBucketName;
                string _Password = DefBucketPassword;
                if (!string.IsNullOrEmpty(bucket))
                {
                    _Bucket = bucket;
                }
                if (!string.IsNullOrEmpty(password))
                {
                    _Password = password;
                };
                 IBucket Bucket = GetBucket(_Bucket, _Password);
                 if (Bucket != null)
                 {
                     var CacheResult = Bucket.Get<object>((AppName + "_" + key).ToLower());
                     result = (CacheResult != null && CacheResult.Success);
                 }
            }
            return result;
        }
    }
}
